<template>
    <div class="mini-spec" @click.native="refreshSpecList">
        <scroll class="specList" :data="Object.keys(showSpec)" :probeType="1" :click="true" ref="specList" :bounce="false">
            <ul>
                <li class="spec-item" v-for="(key, index) in Object.keys(showSpec)" :key="index">
                    <div class="spec-title">{{ key }}</div>
                    <!--多个选项-->
                    <div class="spec-list">
                        <div class="spec-value"
                             v-for="(item, i) in showSpec[key]"
                             :key="i"
                             @click="chooseSpec(key, item)"
                             :class="{no: notSelectable.includes(item),active: selectedArr[key]===item}"
                        >
                            {{ item }}
                        </div>
                    </div>
                    <div class="line"></div>
                </li>
                <div ref="slotKey">
                   <slot></slot>
                </div>
            </ul>
        </scroll>
    </div>
</template>

<script>
    import Scroll from 'common/scroll';
    export default {
        name: "mini-spec",
        props:{
            proContent:{
                type:Object
            }
        },
        components: {Scroll},
        data(){
            return{
                showSpec: {}, //用于展示的规格选项
                reSku: [], //重组后的sku-->[{path: "三人份-BT辣-羊肉-炒",sku: "000UNLI4"},]
                selectedArr:[], //所有选中的规格与key的组合
                curtSelect: '',//当前选中的规格
                notSelectable:[],
                allPath: {},
                keys: this.proContent.key, //所有可选属性行
                selectedCache: [], //已选中的缓存
                spliter: '-', //分隔符
            }
        },
        created(){
            this.refresh();
            this.filterNullSku();
            this.showSpec = this.getshowSpec(this.proContent);
            let arr = this.combineAttr(this.proContent.sku, this.keys);
            this.reSku = arr.items;
            this.buildResult(this.reSku);
            // 只有一个sku时默认选中所有选项
            if(this.proContent.sku.length === 1){
                let sku = this.proContent.sku;
                for (let k in this.selectedArr){
                    this.selectedArr[k] =sku[0][k]
                }
                this.updateStatus(this.getSelectedItem())
            }
            this.$emit('getChoose',this.selectedArr)
        },
        methods:{
            //属性点击事件
            chooseSpec(skey, sval){ //skey->选中的规格key,sval->选中的规格值
                // console.log('skey, sval', skey, sval, this.selectedArr[skey]);
                this.curtSelect = sval;
                if(!this.notSelectable.includes(sval)){
                    if(this.selectedArr[skey] === sval){
                        this.selectedArr[skey] = ''
                    } else {
                        this.selectedArr[skey] = sval
                    }
                    this.updateStatus(this.getSelectedItem());
                    this.$emit('getChoose',this.selectedArr)
                }
            },

            //触发scroll刷新，重新计算dom
            refresh() {
                //触发scroll刷新，重新计算dom
                setTimeout(() => {
                    this.$refs.specList.refresh();
                }, 200);
            },

            //将sku stock为0的sku过滤掉
            filterNullSku() {
                if (this.proContent) {
                    this.proContent.sku = this.proContent.sku.filter((item) => {
                        return item.stock > 0;
                    });
                }
            },

            // 将商品数据中的 sku 用 key 过滤出所有可选的商品规格
            getshowSpec(product) {
                let keys = product['key'];
                let jsons = {};
                let select = {};
                for (let key of keys) {
                    jsons[key] = {};
                    select[key] = '';
                    for (let j = 0; j < product['sku'].length; j++) {
                        jsons[key][product['sku'][j][key]] = 0;
                    }
                }
                this.selectedArr = select; //储存已选属性{颜色:'',尺寸: ''...}
                for (let i in jsons) {
                    let arr = [];
                    for (let j in jsons[i]) {
                        arr.push(j);
                    }
                    jsons[i] = arr;
                }
                return jsons;
            },

            //计算组合数据
            combineAttr(data, keys) {
                let allKeys = []
                for (let i = 0; i < data.length; i++) {
                    let item = data[i]
                    let values = []
                    for (let j = 0; j < keys.length; j++) {
                        values.push(item[keys[j]])
                    }
                    allKeys.push({
                        path: values.join(this.spliter),
                        sku: item['buyid']
                    })
                }
                return {
                    items: allKeys
                }
            },

            //获取所有可选路径
            getAllKeys(arr) {
                let result = []
                for (let i = 0; i < arr.length; i++) { result.push(arr[i].path) }
                return result
            },

            /**
             * 取得集合的所有子集「幂集」
             arr = [1,2,3]

             i = 0, ps = [[]]:
             j = 0; j < ps.length => j < 1:
             i=0, j=0 ps.push(ps[0].concat(arr[0])) => ps.push([].concat(1)) => [1]
             ps = [[], [1]]

             i = 1, ps = [[], [1]] :
             j = 0; j < ps.length => j < 2
             i=1, j=0 ps.push(ps[0].concat(arr[1])) => ps.push([].concat(2))  => [2]
             i=1, j=1 ps.push(ps[1].concat(arr[1])) => ps.push([1].concat(2)) => [1,2]
             ps = [[], [1], [2], [1,2]]

             i = 2, ps = [[], [1], [2], [1,2]]
             j = 0; j < ps.length => j < 4
             i=2, j=0 ps.push(ps[0].concat(arr[2])) => ps.push([3])    => [3]
             i=2, j=1 ps.push(ps[1].concat(arr[2])) => ps.push([1, 3]) => [1, 3]
             i=2, j=2 ps.push(ps[2].concat(arr[2])) => ps.push([2, 3]) => [2, 3]
             i=2, j=3 ps.push(ps[3].concat(arr[2])) => ps.push([2, 3]) => [1, 2, 3]
             ps = [[], [1], [2], [1,2], [3], [1, 3], [2, 3], [1, 2, 3]]
             */
            powerset(arr) {
                let ps = [[]];
                for (let i=0; i < arr.length; i++) {
                    for (let j = 0, len = ps.length; j < len; j++) {
                        ps.push(ps[j].concat(arr[i]));
                    }
                }
                return ps;
            },

            /**
             * 生成所有子集是否可选、库存状态 map
             */
            buildResult(items) {
                let allKeys = this.getAllKeys(items);

                for (let i = 0; i < allKeys.length; i++) {
                    let curr = allKeys[i];
                    let sku = items[i].sku;
                    let values = curr.split(this.spliter);
                    let allSets = this.powerset(values);

                    // 每个组合的子集
                    for (let j = 0; j < allSets.length; j++) {
                        let set = allSets[j]
                        let key = set.join(this.spliter)

                        if (this.allPath[key]) {
                            this.allPath[key].skus.push(sku)
                        } else {
                            this.allPath[key] = {
                                skus: [sku]
                            }
                        }
                    }
                }
            },

            //过滤分隔符
            trimSpliter(str) {
                // ⊙abc⊙ => abc
                // ⊙a⊙⊙b⊙c⊙ => a⊙b⊙c
                let reLeft = new RegExp('^' + this.spliter + '+', 'g');
                let reRight = new RegExp(this.spliter + '+$', 'g');
                let reSpliter = new RegExp(this.spliter + '+', 'g');
                return str.replace(reLeft, '')
                    .replace(reRight, '')
                    .replace(reSpliter, this.spliter)
            },

            //获取当前选中的属性
            getSelectedItem() {
                let result = [];
                result = Object.values(this.selectedArr);
                return result
            },

            //更新所有属性状态
            updateStatus(selected) {
                this.notSelectable =[]
                for (let i = 0; i < this.keys.length; i++) {
                    let key = this.keys[i];
                    let data = this.showSpec[key]
                    let copy = selected.slice()
                    for (let j = 0; j < data.length; j++) {
                        let item = data[j];
                        if (selected[i] === item) continue;
                        copy[i] = item
                        let curr = this.trimSpliter(copy.join(this.spliter), this.spliter);
                        if (!this.allPath[curr]) {
                            this.notSelectable.push(item)
                        }
                    }
                }
                if(!this.getSelectedItem().includes('')){
                    let choSku = this.getSelectedItem().join(this.spliter)
                    this.$emit('findSku', this.allPath[choSku].skus[0])
                    // console.log('this.allPath[curr]',choSku,this.allPath[choSku].skus[0],this.getSelectedItem())
                }
            },

            //无效属性点击
            handleDisableClick($this) {
                let $currAttr = $this.parents('dl').eq(0)
                let idx = $currAttr.data('idx')
                let type = $currAttr.data('type')
                let value = $this.val()

                $this.removeClass('disabled')
                this.selectedCache[idx] = value

                console.log(this.selectedCache)
                // 清空高亮行的已选属性状态（因为更新的时候默认会跳过已选状态）
                $('dl').not($currAttr).find('button').removeClass('active')
                updateStatus(getSelectedItem())

                /**
                 * 恢复原来已选属性
                 * 遍历所有非当前属性行
                 *   1. 与 selectedCache 对比
                 *   2. 如果要恢复的属性存在（非 disable）且 和当前*未高亮行*已选择属性的*可组合*），高亮原来已选择的属性且更新
                 *   3. 否则什么也不做
                 */
                for (let i = 0; i < this.keys.length; i++) {
                    let item = this.keys[i]
                    let $curr = $('dl[data-type="'+ item +'"]')
                    if (item == type) continue

                    let $lastSelected = $curr.find('button[value="'+ this.selectedCache[i] +'"]')

                    // 缓存的已选属性没有 disabled (可以被选择)
                    if (!$lastSelected.hasClass('disabled')) {
                        $lastSelected.addClass('active')
                        updateStatus(getSelectedItem())
                    }
                }

            },
        },
    }
</script>

<style lang="stylus" scoped>
    @import '~@/assets/main.styl'

    .mini-spec {
        position relative
        width 100%
        padding-top smallMargin
        max-height vh(400)
        .specList {
            background-color grayF
            position relative
            width 100vw
            max-height vh(400)
            overflow-x hidden
            .spec-item {
                position relative
                margin middleMargin 0
                word-vw(word16, gary3)
                .spec-title{
                    max-width vw(345)
                    ellipsis()
                }
                .spec-list{
                    display flex
                    flex-flow row wrap
                    .spec-value{
                        top bigMargin
                        word-vw(word16, gary3)
                        display flex
                        justify-content center
                        text-align center
                        align-items center
                        min-width (90/3.75)vw
                        max-width vw(345)
                        ellipsis()
                        height (30/3.75)vw
                        border-radius 30px
                        box-sizing border-box
                        line-height (30/3.75)vw
                        border none
                        background-color grayE
                        color gray3
                        margin-right middleMargin
                        margin-top smallMargin

                        &.no {
                            color gray9
                            border-color gray9
                            /*color blue*/
                        }
                        &.active {
                            min-width vw(90)
                            max-width vw(345)
                            ellipsis()
                            height (30/3.75)vw
                            background-color main-color
                            text-align center
                            line-height (30/3.75)vw
                            border-radius 30px
                            color grayF
                            top bigMargin
                            word-vw(word16, gary3)
                        }
                    }
                }
            }
            .line {
                line()
                position absolute
                margin-top smallMargin
            }
        }

    }
</style>
